<!DOCTYPE html>

<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width">
	<title>messageformat Source: messageformat/src/messageformat.js</title>

	<!--[if lt IE 9]>
	<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
	<![endif]-->
	<link type="text/css" rel="stylesheet" href="styles/sunlight.default.css">

	<link type="text/css" rel="stylesheet" href="styles/site.flatly.css">

	<link rel='apple-touch-icon' sizes='180x180' href='logo/favicon-180.png'>
<link rel='icon' type='image/png' sizes='32x32' href='logo/favicon-32.png'>
</head>

<body>

<div class="navbar navbar-default navbar-fixed-top ">
<div class="container">
	<div class="navbar-header">
		<a class="navbar-brand" href="./"><img class="branding-logo" src="logo/messageformat.svg"
		alt="logo"/>messageformat</a>
		<button class="navbar-toggle" type="button" data-toggle="collapse" data-target="#topNavigation">
			<span class="icon-bar"></span>
			<span class="icon-bar"></span>
			<span class="icon-bar"></span>
        </button>
	</div>
	<div class="navbar-collapse collapse" id="topNavigation">
		<ul class="nav navbar-nav">
			
			<li class="dropdown">
				<a href="classes.list" class="dropdown-toggle" data-toggle="dropdown">Classes<b class="caret"></b></a>
				<ul class="dropdown-menu ">
					<li><a href="Formatters">Formatters</a></li><li><a href="MessageFormat">MessageFormat</a></li><li><a href="Messages">Messages</a></li>
				</ul>
			</li>
			
				
					<li class="nav-item">
						<a class="nav-link" href="page-about">About</a>
					</li>
				
					<li class="nav-item">
						<a class="nav-link" href="page-build">Usage</a>
					</li>
				
					<li class="nav-item">
						<a class="nav-link" href="page-guide">Format Guide</a>
					</li>
				
			
		</ul>
        
        
          <ul class="nav navbar-nav navbar-right">
            
              <li><a href="https://github.com/messageformat/messageformat/releases">2.2.1</a></li>
            
            <li class="navbar-github-icon"><a href="https://github.com/messageformat/messageformat">
              <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                <title>messageformat on GitHub</title>
                <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
              </svg>
            </a></li>
          </ul>
        
	</div>

</div>
</div>


<div class="container" id="toc-content">
<div class="row">

	
	<div class="col-md-12">
	
		<div id="main">
			

		<h1 class="page-title">Source: messageformat/src/messageformat.js</h1>
    
<section>
    <article>
        <pre
            class="sunlight-highlight-javascript ">import Formatters from 'messageformat-formatters';
import Compiler from './compiler';
import { funcname, propname } from './utils';
import { getAllPlurals, getPlural } from './plurals';
import Runtime from './runtime';

export default class MessageFormat {
  /**
   * The default locale
   *
   * Used by the constructor when no `locale` has been set to initialise the value
   * of its instance counterpart, `MessageFormat#defaultLocale`.
   *
   * @memberof MessageFormat
   * @default 'en'
   */
  static defaultLocale = 'en';

  /** Escape special characaters
   *
   *  Surround the characters `{` and `}` in the input string with 'quotes'.
   *  This will allow those characters to not be considered as MessageFormat
   *  control characters.
   *
   * @memberof MessageFormat
   * @param {string} str - The input string
   * @param {boolean} [octothorpe=false] - Include `#` in the escaped characters
   * @returns {string} The escaped string
   */
  static escape(str, octothorpe) {
    const esc = octothorpe ? /[#{}]/g : /[{}]/g;
    return String(str).replace(esc, "'$&amp;'");
  }

  static formatters = Formatters;

  /**
   * Create a new MessageFormat compiler
   *
   * If set, the `locale` parameter limits the compiler to use a subset of the 204
   * languages' pluralisation rules made available by the Unicode CLDR.
   *
   * Leaving `locale` undefined or using an array of strings will create a
   * MessageFormat instance with multi-language support. To select which to use,
   * use the second parameter of `{@link MessageFormat#compile compile()}`, or use
   * message keys corresponding to your locales. The default locale will be the
   * first entry of the array, or `{@link MessageFormat.defaultLocale defaultLocale}`
   * if not set.
   *
   * A string `locale` will create a single-locale MessageFormat instance.
   *
   * Using an object `locale` with all properties of type `function` allows for
   * the use of custom or externally defined pluralisation rules; in this case
   *
   * @class MessageFormat
   * @classdesc MessageFormat-to-JavaScript compiler
   * @param {string|string[]|Object} [locale] - The locale(s) to use
   *
   * ```
   * import MessageFormat from 'messageformat'
   * ```
   */
  constructor(locale) {
    this.pluralFuncs = {};
    if (typeof locale === 'string') {
      this.pluralFuncs[locale] = getPlural(locale);
      this.defaultLocale = locale;
    } else if (Array.isArray(locale)) {
      locale.forEach(lc => {
        this.pluralFuncs[lc] = getPlural(lc);
      });
      this.defaultLocale = locale[0];
    } else {
      for (const lc in locale)
        if (locale.hasOwnProperty(lc)) {
          if (typeof locale[lc] !== 'function') {
            throw new Error(
              'Expected function value for locale ' + JSON.stringify(lc)
            );
          }
          this.pluralFuncs[lc] = locale[lc];
          if (!this.defaultLocale) this.defaultLocale = lc;
        }
      if (this.defaultLocale) {
        this.hasCustomPluralFuncs = true;
      } else {
        this.defaultLocale = MessageFormat.defaultLocale;
      }
    }
    this.fmt = {};
    this.runtime = new Runtime(this);
  }

  /**
   * Add custom formatter functions to this MessageFormat instance. See the
   * {@page guide} for more details.
   *
   * The general syntax for calling a formatting function in MessageFormat is
   * `{var, fn[, arg]}`, where `var` is the variable that will be set by the
   * user code, `fn` determines the formatting function, and `arg` is an
   * optional string argument.
   *
   * In JavaScript, each formatting function is called with three parameters;
   * the variable value `v`, the current locale `lc`, and `arg` as a string, or
   * undefined if not set. `arg` will be trimmed of surrounding whitespace.
   * Formatting functions should not have side effects.
   *
   * @memberof MessageFormat
   * @instance
   * @param {Object.&lt;string,function>} fmt - A map of formatting functions
   * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
   *
   * @example
   * const mf = new MessageFormat('en-GB')
   * mf.addFormatters({
   *   upcase: function(v) { return v.toUpperCase() },
   *   locale: function(v, lc) { return lc },
   *   prop: function(v, lc, p) { return v[p] }
   * })
   * const messages = mf.compile({
   *   describe: 'This is {VAR, upcase}.',
   *   locale: 'The current locale is {_, locale}.',
   *   answer: 'Answer: {obj, prop, a}'
   * }
   *
   * messages.describe({ VAR: 'big' })        // 'This is BIG.'
   * messages.locale({})                      // 'The current locale is en-GB.'
   * messages.answer({ obj: {q: 3, a: 42} })  // 'Answer: 42'
   */
  addFormatters(fmt) {
    for (const name in fmt)
      if (fmt.hasOwnProperty(name)) this.fmt[name] = fmt[name];
    return this;
  }

  /**
   * Disable the validation of plural &amp; selectordinal keys
   *
   * Previous versions of messageformat allowed the use of plural &amp;
   * selectordinal statements with any keys; now we throw an error when a
   * statement uses a non-numerical key that will never be matched as a
   * pluralization category for the current locale.
   *
   * Use this method to disable the validation and allow usage as previously.
   * To re-enable, you'll need to create a new MessageFormat instance.
   *
   * @memberof MessageFormat
   * @instance
   * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
   *
   * @example
   * const mf = new MessageFormat('en')
   * const msg = '{X, plural, zero{no answers} one{an answer} other{# answers}}'
   *
   * mf.compile(msg)
   * // Error: Invalid key `zero` for argument `X`. Valid plural keys for this
   * //        locale are `one`, `other`, and explicit keys like `=0`.
   *
   * mf.disablePluralKeyChecks()
   * mf.compile(msg)({ X: 0 })  // '0 answers'
   */
  disablePluralKeyChecks() {
    this.noPluralKeyChecks = true;
    for (const lc in this.pluralFuncs) {
      const pf = this.pluralFuncs[lc];
      if (pf) {
        pf.cardinal = [];
        pf.ordinal = [];
      }
    }
    return this;
  }

  /**
   * Enable or disable the addition of Unicode control characters to all input
   * to preserve the integrity of the output when mixing LTR and RTL text.
   *
   * @see http://cldr.unicode.org/development/development-process/design-proposals/bidi-handling-of-structured-text
   *
   * @memberof MessageFormat
   * @instance
   * @param {boolean} [enable=true]
   * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
   *
   * @example
   * // upper case stands for RTL characters, output is shown as rendered
   * const mf = new MessageFormat('en')
   *
   * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD'])
   *   // 'first >> THIRD &lt;&lt; SECOND'
   *
   * mf.setBiDiSupport(true)
   * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD'])
   *   // 'first >> SECOND >> THIRD'
   */
  setBiDiSupport(enable) {
    this.bidiSupport = !!enable || typeof enable == 'undefined';
    return this;
  }

  /**
   * According to the ICU MessageFormat spec, a `#` character directly inside a
   * `plural` or `selectordinal` statement should be replaced by the number
   * matching the surrounding statement. By default, messageformat will replace
   * `#` signs with the value of the nearest surrounding `plural` or
   * `selectordinal` statement.
   *
   * Set this to true to follow the stricter ICU MessageFormat spec, and to
   * throw a runtime error if `#` is used with non-numeric input.
   *
   * @memberof MessageFormat
   * @instance
   * @param {boolean} [enable=true]
   * @returns {MessageFormat} The MessageFormat instance, to allow for chaining
   *
   * @example
   * const mf = new MessageFormat('en')
   * const src = {
   *   cookie: '#: {X, plural, =0{no cookies} one{a cookie} other{# cookies}}',
   *   pastry: `{X, plural,
   *     one {{P, select, cookie{a cookie} other{a pie}}}
   *     other {{P, select, cookie{# cookies} other{# pies}}}
   *   }`
   * }
   * let messages = mf.compile(src)
   *
   * messages.cookie({ X: 3 })            // '#: 3 cookies'
   * messages.pastry({ X: 3, P: 'pie' })  // '3 pies'
   *
   * mf.setStrictNumberSign(true)
   * messages = mf.compile(src)
   * messages.pastry({ X: 3, P: 'pie' })  // '# pies'
   */
  setStrictNumberSign(enable) {
    this.strictNumberSign = !!enable || typeof enable == 'undefined';
    this.runtime.setStrictNumber(this.strictNumberSign);
    return this;
  }

  /**
   * Compile messages into storable functions
   *
   * If `messages` is a single string including ICU MessageFormat declarations,
   * the result of `compile()` is a function taking a single Object parameter
   * `d` representing each of the input's defined variables.
   *
   * If `messages` is a hierarchical structure of such strings, the output of
   * `compile()` will match that structure, with each string replaced by its
   * corresponding JavaScript function.
   *
   * If the input `messages` -- and therefore the output -- of `compile()` is an
   * object, the output object will have a `toString(global)` method that may be
   * used to store or cache the compiled functions to disk, for later inclusion
   * in any JS environment, without a local MessageFormat instance required. If
   * its `global` parameter is null or undefined, the result is an ES6 module
   * with a default export. If `global` is a string containing `.`, the result
   * will be a script setting its value. Otherwise, the output defaults to an UMD
   * pattern that sets the value of `global` if used outside of AMD and CommonJS
   * loaders.
   *
   * If `locale` is not set, it will default to
   * `{@link MessageFormat.defaultLocale defaultLocale}`; using a key at any
   * depth of `messages` that is a declared locale will set its child elements to
   * use that locale.
   *
   * If `locale` is set, it is used for all messages, ignoring any otherwise
   * matching locale keys. If the constructor declared any locales, `locale`
   * needs to be one of them.
   *
   * If `compile()` is called with a `messages` object on a MessageFormat
   * instance that does not specify any locales, it will match keys to *all* 204
   * available locales. This is really useful if you want your messages to be
   * completely determined by your data, but may provide surprising results if
   * your input includes any 2-3 letter strings that are not locale identifiers.
   *
   * @memberof MessageFormat
   * @instance
   * @param {string|Object} messages - The input message(s) to be compiled, in ICU MessageFormat
   * @param {string} [locale] - A locale to use for the messages
   * @returns {function|Object} The first match found for the given locale(s)
   *
   * @example
   * const mf = new MessageFormat('en')
   * const msg = mf.compile('A {TYPE} example.')
   *
   * msg({ TYPE: 'simple' })  // 'A simple example.'
   *
   * @example
   * const mf = new MessageFormat(['en', 'fi'])
   * const messages = mf.compile({
   *   en: { a: 'A {TYPE} example.',
   *         b: 'This is the {COUNT, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} example.' },
   *   fi: { a: '{TYPE} esimerkki.',
   *         b: 'Tämä on {COUNT, selectordinal, other{#.}} esimerkki.' }
   * })
   *
   * messages.en.b({ COUNT: 2 })  // 'This is the 2nd example.'
   * messages.fi.b({ COUNT: 2 })  // 'Tämä on 2. esimerkki.'
   *
   * @example
   * const fs = require('fs')
   * const mf = new MessageFormat('en')
   * const msgSet = {
   *   a: 'A {TYPE} example.',
   *   b: 'This has {COUNT, plural, one{one member} other{# members}}.',
   *   c: 'We have {P, number, percent} code coverage.'
   * }
   * const msgStr = mf.compile(msgSet).toString('module.exports')
   * fs.writeFileSync('messages.js', msgStr)
   *
   * ...
   *
   * const messages = require('./messages')
   *
   * messages.a({ TYPE: 'more complex' })  // 'A more complex example.'
   * messages.b({ COUNT: 3 })              // 'This has 3 members.'
   */
  compile(messages, locale) {
    function _stringify(obj, level) {
      if (!level) level = 0;
      if (typeof obj != 'object') return obj;
      let indent = '';
      for (let i = 0; i &lt; level; ++i) indent += '  ';
      const o = [];
      for (const k in obj) {
        const v = _stringify(obj[k], level + 1);
        o.push(`\n${indent}  ${propname(k)}: ${v}`);
      }
      return `{${o.join(',')}\n${indent}}`;
    }

    let pf = {};
    if (Object.keys(this.pluralFuncs).length === 0) {
      if (locale) {
        const pfn0 = getPlural(locale, this.noPluralKeyChecks);
        if (!pfn0) {
          const lcs = JSON.stringify(locale);
          throw new Error(`Locale ${lcs} not found!`);
        }
        pf[locale] = pfn0;
      } else {
        locale = this.defaultLocale;
        pf = getAllPlurals(this.noPluralKeyChecks);
      }
    } else if (locale) {
      const pfn1 = this.pluralFuncs[locale];
      if (!pfn1) {
        const lcs = JSON.stringify(locale);
        const pfs = JSON.stringify(this.pluralFuncs);
        throw new Error(`Locale ${lcs} not found in ${pfs}!`);
      }
      pf[locale] = pfn1;
    } else {
      locale = this.defaultLocale;
      pf = this.pluralFuncs;
    }

    const compiler = new Compiler(this);
    const obj = compiler.compile(messages, locale, pf);

    if (typeof messages != 'object') {
      const fn = new Function(
        'number, plural, select, fmt',
        funcname(locale),
        'return ' + obj
      );
      const rt = this.runtime;
      return fn(rt.number, rt.plural, rt.select, this.fmt, pf[locale]);
    }

    const rtStr = this.runtime.toString(pf, compiler) + '\n';
    const objStr = _stringify(obj);
    const result = new Function(rtStr + 'return ' + objStr)();
    if (result.hasOwnProperty('toString'))
      throw new Error('The top-level message key `toString` is reserved');

    result.toString = function(global) {
      if (!global || global === 'export default') {
        return rtStr + 'export default ' + objStr;
      } else if (global.indexOf('.') > -1) {
        return rtStr + global + ' = ' + objStr;
      } else {
        return (
          rtStr +
          [
            '(function (root, G) {',
            '  if (typeof define === "function" &amp;&amp; define.amd) { define(G); }',
            '  else if (typeof exports === "object") { module.exports = G; }',
            '  else { ' + propname(global, 'root') + ' = G; }',
            '})(this, ' + objStr + ');'
          ].join('\n')
        );
      }
    };
    return result;
  }
}
</pre>
    </article>
</section>





		</div>
	</div>

	<div class="clearfix"></div>

	

</div>
</div>



<footer>


</footer>

<script src="scripts/docstrap.lib.js"></script>
<script src="scripts/toc.js"></script>


<script>
$( function () {
	$( "[id*='$']" ).each( function () {
		var $this = $( this );

		$this.attr( "id", $this.attr( "id" ).replace( "$", "__" ) );
	} );

	$( ".page-section pre, .readme-section pre, pre.prettyprint.source" ).each( function () {
		var $this = $( this );

		var example = $this.find( "code" );
		exampleText = example.html();
		var lang = /{@lang (.*?)}/.exec( exampleText );
		if ( lang && lang[1] ) {
			exampleText = exampleText.replace( lang[0], "" );
			example.html( exampleText );
			lang = lang[1];
		} else {
			var langClassMatch = example.parent()[0].className.match(/lang\-(\S+)/);
			lang = langClassMatch ? langClassMatch[1] : "javascript";
		}

		if ( lang ) {

			$this
			.addClass( "sunlight-highlight-" + lang )
			.addClass( "linenums" )
			.html( example.html() );

		}
	} );

	Sunlight.highlightAll( {
		lineNumbers : false,
		showMenu : true,
		enableDoclinks : true
	} );

	$.catchAnchorLinks( {
        navbarOffset: 10
	} );
	$( "#toc" ).toc( {
		anchorName  : function ( i, heading, prefix ) {
			return $( heading ).attr( "id" ) || ( prefix + i );
		},
		selectors   : "#toc-content h1,#toc-content h2,#toc-content h3,#toc-content h4",
		showAndHide : false,
		smoothScrolling: true
	} );

	$( "#main span[id^='toc']" ).addClass( "toc-shim" );
	$( '.dropdown-toggle' ).dropdown();

    $( "table" ).each( function () {
      var $this = $( this );
      $this.addClass('table');
    } );

} );
</script>



<!--Navigation and Symbol Display-->


<!--Google Analytics-->




</body>
</html>
